package com.terracloud.server.controller;

import com.terracloud.server.config.MetricsProperties;
import com.terracloud.server.config.annotations.ApiOperation;
import com.terracloud.server.queue.util.TbCoreComponent;
import com.terracloud.server.service.stats.PhysicalMetricsService;
import com.terracloud.server.service.stats.PrometheusMetricsQueryService;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.util.Map;

/**
 * 物理资源监控指标控制器
 * 提供物理资源监控指标的管理接口
 */
@Tag(name = "Physical Metrics", description = "物理资源监控指标管理接口")
@RestController
@TbCoreComponent
@RequestMapping(value = "/api/device/metrics", produces = MediaType.APPLICATION_JSON_VALUE)
@RequiredArgsConstructor
@Slf4j
public class PhysicalMetricsController {

    private final PhysicalMetricsService physicalMetricsService;
    private final PrometheusMetricsQueryService prometheusMetricsQueryService;
    private final MetricsProperties metricsProperties;

    /**
     * 手动触发一次物理资源指标收集和上报
     *
     * @return 操作结果
     */
    @ApiOperation(value = "触发指标收集", notes = "手动触发一次物理资源指标收集和上报")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "操作成功",
                    content = @Content(schema = @Schema(implementation = String.class))),
            @ApiResponse(responseCode = "500", description = "服务器内部错误",
                    content = @Content(schema = @Schema(implementation = String.class)))
    })
    @PreAuthorize("hasAuthority('TENANT_ADMIN')")
    @RequestMapping(value = "/collect", method = RequestMethod.POST)
    public ResponseEntity<String> collectMetrics() {
        try {
            physicalMetricsService.collectAndPushMetrics();
            log.info("手动触发物理资源指标收集成功");
            return ResponseEntity.ok("物理资源指标收集并上报成功");
        } catch (Exception e) {
            log.error("手动触发物理资源指标收集失败", e);
            return ResponseEntity.status(500).body("物理资源指标收集或上报失败: " + e.getMessage());
        }
    }

    /**
     * 单独上报CPU使用情况数据
     *
     * @return 操作结果
     */
    @ApiOperation(value = "上报CPU使用情况", notes = "单独手动上报一条系统CPU使用情况的数据")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "操作成功",
                    content = @Content(schema = @Schema(implementation = String.class))),
            @ApiResponse(responseCode = "500", description = "服务器内部错误",
                    content = @Content(schema = @Schema(implementation = String.class)))
    })
    @PreAuthorize("hasAuthority('TENANT_ADMIN')")
    @RequestMapping(value = "/cpu", method = RequestMethod.POST)
    public ResponseEntity<String> reportCpuUsage() {
        try {
            // 收集并推送CPU指标
            physicalMetricsService.collectAndPushCpuMetricOnly();
            log.info("手动触发CPU使用情况数据上报成功");
            return ResponseEntity.ok("CPU使用情况数据上报成功");
        } catch (Exception e) {
            log.error("手动触发CPU使用情况数据上报失败", e);
            return ResponseEntity.status(500).body("CPU使用情况数据上报失败: " + e.getMessage());
        }
    }

    /**
     * 单独上报内存使用情况数据
     *
     * @return 操作结果
     */
    @ApiOperation(value = "上报内存使用情况", notes = "单独手动上报一条系统内存使用情况的数据")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "操作成功",
                    content = @Content(schema = @Schema(implementation = String.class))),
            @ApiResponse(responseCode = "500", description = "服务器内部错误",
                    content = @Content(schema = @Schema(implementation = String.class)))
    })
    @PreAuthorize("hasAuthority('TENANT_ADMIN')")
    @RequestMapping(value = "/memory", method = RequestMethod.POST)
    public ResponseEntity<String> reportMemoryUsage() {
        try {
            // 收集并推送内存指标
            physicalMetricsService.collectAndPushMemoryMetricOnly();
            log.info("手动触发内存使用情况数据上报成功");
            return ResponseEntity.ok("内存使用情况数据上报成功");
        } catch (Exception e) {
            log.error("手动触发内存使用情况数据上报失败", e);
            return ResponseEntity.status(500).body("内存使用情况数据上报失败: " + e.getMessage());
        }
    }

    /**
     * 单独上报磁盘使用情况数据
     *
     * @return 操作结果
     */
    @ApiOperation(value = "上报磁盘使用情况", notes = "单独手动上报一条系统磁盘使用情况的数据")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "操作成功",
                    content = @Content(schema = @Schema(implementation = String.class))),
            @ApiResponse(responseCode = "500", description = "服务器内部错误",
                    content = @Content(schema = @Schema(implementation = String.class)))
    })
    @PreAuthorize("hasAuthority('TENANT_ADMIN')")
    @RequestMapping(value = "/disk", method = RequestMethod.POST)
    public ResponseEntity<String> reportDiskUsage() {
        try {
            // 收集并推送磁盘指标
            physicalMetricsService.collectAndPushDiskMetricOnly();
            log.info("手动触发磁盘使用情况数据上报成功");
            return ResponseEntity.ok("磁盘使用情况数据上报成功");
        } catch (Exception e) {
            log.error("手动触发磁盘使用情况数据上报失败", e);
            return ResponseEntity.status(500).body("磁盘使用情况数据上报失败: " + e.getMessage());
        }
    }

    /**
     * 单独上报网络使用情况数据
     *
     * @return 操作结果
     */
    @ApiOperation(value = "上报网络使用情况", notes = "单独手动上报一条系统网络使用情况的数据")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "操作成功",
                    content = @Content(schema = @Schema(implementation = String.class))),
            @ApiResponse(responseCode = "500", description = "服务器内部错误",
                    content = @Content(schema = @Schema(implementation = String.class)))
    })
    @PreAuthorize("hasAuthority('TENANT_ADMIN')")
    @RequestMapping(value = "/network", method = RequestMethod.POST)
    public ResponseEntity<String> reportNetworkUsage() {
        try {
            // 收集并推送网络指标
            physicalMetricsService.collectAndPushNetworkMetricOnly();
            log.info("手动触发网络使用情况数据上报成功");
            return ResponseEntity.ok("网络使用情况数据上报成功");
        } catch (Exception e) {
            log.error("手动触发网络使用情况数据上报失败", e);
            return ResponseEntity.status(500).body("网络使用情况数据上报失败: " + e.getMessage());
        }
    }

    /**
     * 更新标签信息
     *
     * @param tenantId 租户ID
     * @param nodeName 节点名称
     * @return 操作结果
     */
    @ApiOperation(value = "更新标签信息", notes = "更新物理资源指标的标签信息")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "操作成功",
                    content = @Content(schema = @Schema(implementation = String.class))),
            @ApiResponse(responseCode = "400", description = "参数错误",
                    content = @Content(schema = @Schema(implementation = String.class)))
    })
    @PreAuthorize("hasAuthority('TENANT_ADMIN')")
    @RequestMapping(value = "/labels", method = RequestMethod.PUT)
    public ResponseEntity<String> updateLabels(
            @RequestParam String tenantId,
            @RequestParam String nodeName) {
        try {
            if (tenantId == null || tenantId.isEmpty()) {
                return ResponseEntity.badRequest().body("租户ID不能为空");
            }
            if (nodeName == null || nodeName.isEmpty()) {
                return ResponseEntity.badRequest().body("节点名称不能为空");
            }

            physicalMetricsService.updateLabels(tenantId, nodeName);
            log.info("更新标签信息成功: tenantId={}, nodeName={}", tenantId, nodeName);
            return ResponseEntity.ok("标签信息更新成功");
        } catch (Exception e) {
            log.error("更新标签信息失败", e);
            return ResponseEntity.status(500).body("更新标签信息失败: " + e.getMessage());
        }
    }

    /**
     * 获取当前指标收集配置状态
     *
     * @return 配置状态信息
     */
    @ApiOperation(value = "获取指标配置", notes = "获取当前物理资源指标收集的配置状态")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "操作成功",
                    content = @Content(schema = @Schema(implementation = MetricsProperties.class)))
    })
    @PreAuthorize("hasAuthority('TENANT_ADMIN')")
    @RequestMapping(value = "/config", method = RequestMethod.GET)
    public ResponseEntity<MetricsConfigResponse> getMetricsConfig() {
        log.info("获取指标配置信息");
        MetricsConfigResponse response = new MetricsConfigResponse();
        response.setUrl(metricsProperties.getUrl());
        response.setJobName(metricsProperties.getJobName());
        response.setInstanceId(metricsProperties.getInstanceId());
        response.setEnabled(metricsProperties.isEnabled());
        response.setRuntimeEnabled(physicalMetricsService.isRuntimeEnabled());
        return ResponseEntity.ok(response);
    }

    /**
     * 启用或禁用指标收集功能
     *
     * @param enabled 是否启用
     * @return 操作结果
     */
    @ApiOperation(value = "设置指标收集状态", notes = "启用或禁用物理资源指标收集功能")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "操作成功",
                    content = @Content(schema = @Schema(implementation = String.class)))
    })
    @PreAuthorize("hasAuthority('TENANT_ADMIN')")
    @RequestMapping(value = "/enabled", method = RequestMethod.POST)
    public ResponseEntity<String> setMetricsEnabled(@RequestParam boolean enabled) {
        physicalMetricsService.setRuntimeEnabled(enabled);
        log.info("设置指标收集状态为: {}", enabled);
        return ResponseEntity.ok("指标收集功能已" + (enabled ? "启用" : "禁用"));
    }
    
    /**
     * 查询设备指标数据
     *
     * @param deviceId 设备ID
     * @return 设备指标数据
     */
    @ApiOperation(value = "查询设备指标", notes = "从Prometheus查询设备的指标数据")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "操作成功",
                    content = @Content(schema = @Schema(implementation = Map.class))),
            @ApiResponse(responseCode = "400", description = "参数错误",
                    content = @Content(schema = @Schema(implementation = String.class))),
            @ApiResponse(responseCode = "500", description = "服务器内部错误",
                    content = @Content(schema = @Schema(implementation = String.class)))
    })
    @PreAuthorize("hasAuthority('TENANT_ADMIN')")
    @RequestMapping(value = "/query/{deviceId}", method = RequestMethod.GET)
    public ResponseEntity<Map<String, Object>> queryDeviceMetrics(@PathVariable String deviceId) {
        try {
            if (deviceId == null || deviceId.isEmpty()) {
                return ResponseEntity.badRequest().build();
            }
            
            Map<String, Object> metrics = prometheusMetricsQueryService.queryDeviceMetrics(deviceId);
            return ResponseEntity.ok(metrics);
        } catch (Exception e) {
            log.error("查询设备{}指标数据失败", deviceId, e);
            return ResponseEntity.status(500).build();
        }
    }
    
    /**
     * 指标配置响应类
     */
    @Setter
    @Getter
    public static class MetricsConfigResponse {
        // Getters and setters
        private String url;
        private String jobName;
        private String instanceId;
        private boolean enabled;
        private boolean runtimeEnabled;

    }
}